package com.feng.util;

import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class ObjectUtil {
    @SneakyThrows
    public static boolean isEquals(Object o1, Object o2) {
        if (o1 == null && o2 == null) {
            return true;
        }
        if (o1 == null || o2 == null) {
            return false;
        }
        if (o1 == o2) {
            return true;
        }
        if (o1.getClass().isInstance(o2)) {
            Object p1;
            Object p2;
            Field[] o1DeclaredFields = getAllFields(o1.getClass());
            for (Field o1DeclaredField : o1DeclaredFields) {
                o1DeclaredField.setAccessible(true);
                p1 = o1DeclaredField.get(o1);
                p2 = o1DeclaredField.get(o2);
                if (p1 == null && p2 == null) {
                    continue;
                }
                if (p1 == null || p2 == null) {
                    return false;
                }
                if (!p1.equals(p2)) {
                    return false;
                }
            }
        } else return false;
        return true;
    }

    @SneakyThrows
    public static boolean isEqualsExceptId(Object o1, Object o2) {
        if (o1 == null && o2 == null) {
            return true;
        }
        if (o1 == null || o2 == null) {
            return false;
        }
        if (o1 == o2) {
            return true;
        }
        if (o1.getClass().isInstance(o2)) {
            Object p1;
            Object p2;
            Field[] o1DeclaredFields = getAllFields(o1.getClass());
            for (Field o1DeclaredField : o1DeclaredFields) {
                if (o1DeclaredField.getName().equals("id")) {
                    continue;
                }
                o1DeclaredField.setAccessible(true);
                p1 = o1DeclaredField.get(o1);
                p2 = o1DeclaredField.get(o2);
                if (p1 == null && p2 == null) {
                    continue;
                }
                if (p1 == null || p2 == null) {
                    return false;
                }
                if (!p1.equals(p2)) {
                    return false;
                }
            }
        } else return false;
        return true;
    }

    @SneakyThrows
    public static Field[] getAllFields(Class c) {
        List<Field> o1FieldList = new ArrayList<>();
        while (c != null) {
            o1FieldList.addAll(Arrays.asList(c.getDeclaredFields()));
            c = c.getSuperclass();
        }
        Field[] declaredFields = new Field[o1FieldList.size()];
        o1FieldList.toArray(declaredFields);
        return declaredFields;
    }

    @SneakyThrows
    public static <T> T mapToPojo(Map<String, Object> map, Class<T> clazz, T object) {
//        T object = clazz.getDeclaredConstructor().newInstance();
        Field[] allFields = getAllFields(clazz);
        for (Field field : allFields) {

            int modifiers = field.getModifiers();
            if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
                continue;
            }
            field.setAccessible(true);
            if (!field.getType().getName().equals("java.math.BigDecimal")) {
                field.set(object, map.get(field.getName()));
            } else {
                String s = map.get(field.getName()).toString();
                Double o = Double.valueOf(s);
                BigDecimal bigDecimal = BigDecimal.valueOf(o).setScale(2, RoundingMode.HALF_UP);
                field.set(object, bigDecimal);
            }

        }
        return object;
    }
}
